using System;
using System.Buffers;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Game.modules.player;
using GameFramework;
using GameFramework.common;
using GameFramework.configs;
using GameFramework.net;
using GameFramework.net.handler;
using GameFramework.net.msgserializer;
using GameFramework.scripts;
using UnityEngine;
using Object = System.Object;

public class TcpClient:MonoSingleton<TcpClient>
{
    private LengthFieldBasedFrameDecoder msgHandler = new LengthFieldBasedFrameDecoder();
    //TODO ip和端口应该在配置文件配置
    public String ip;

    public int port;

    private MsgPipeLine msgPipline = new MsgPipeLine();
    private Action<MsgPipeLine> msgPipeLineInitailizer;
    private BlockingCollection<MsgWrapper> sendQueue = new BlockingCollection<MsgWrapper>();
    private BlockingCollection<MsgWrapper> receiveQueue = new BlockingCollection<MsgWrapper>();
    public Socket socket;

    public long playerId;//此连接关联的客户端playerId
    private Thread r_thread;

    private Thread s_thread;
    //连接状态
    public int status  = 1;//1未连接 2连接成功；3连接失败；4.断开连接；5.断开重连中

    public void initPipeline(Action<MsgPipeLine> pipelineInit)
    {
        if (pipelineInit != null)
        {
            this.msgPipeLineInitailizer = pipelineInit;
        }
    }

    // 连接远程服务器
    public void Connect(Action success = null,Action<Exception> fail = null)
    {
        if (status == 2)
        {
            return;
        }

        //点击开始监听时 在服务端创建一个负责监听IP和端口号的Socket
        try
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipRef = IPAddress.Parse(ip);
            IPEndPoint point = new IPEndPoint(ipRef, port);   //创建对象端口
        
            socket.Connect(point);
            status = 2;
            if (msgPipeLineInitailizer != null)
            {
                try
                {
                    msgPipeLineInitailizer.Invoke(msgPipline);
                }
                catch (Exception e)
                {
                    UnityEngine.Debug.LogError(e);
                }
            }

            Debug.Log("连接成功 , " + " ip = " + ip + " port = " + port);
            if (success != null)
            {
                success.Invoke();
            }
            
            r_thread = new Thread(ReceiveMsgFromServer);             //开启新的线程，不停的接收服务器发来的消息
            r_thread.IsBackground = true;
            r_thread.Start();

            s_thread = new Thread(SendMsgToServer);          //开启新的线程，不停的给服务器发送消息
            s_thread.IsBackground = true;
            s_thread.Start();
        }
        catch (Exception e)
        {
            status = 3;
            if (fail != null)
            {
                fail.Invoke(e);
            }
            Debug.LogError(e);
        }


    }

    private void Update()
    {
        if (receiveQueue.Count == 0)
        {
            return;
        }

        int count = 100;//一帧最多处理的消息数，放置一次处理太多卡住了，这个值具体多少还得测试
        MsgWrapper msgWrapper = null;
        while (receiveQueue.TryTake(out msgWrapper))
        {
            int msgId = msgWrapper.msgId;
            Type msgType = MsgManager.Instance.getMsgType(msgId);
            if (msgType == null)
            {
                continue;
            }

            IScript msgScript = MsgManager.Instance.getMsgScript(msgType);
            try
            {
                long playerId = TcpClient.Instance.playerId;
                //TODO 从player管理器中获取player数据
                Player player = PlayerManager.Instance.getPlayer(playerId);
                msgScript.handle(player,msgWrapper.deSerialize);
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
            count--;
            if (count <= 0)
            {
                break;
            }
        }
    }

    public void getMsg(out MsgWrapper msg)
    {
        receiveQueue.TryTake(out msg);
    }

    public void sendMsg(object msg)
    {

        //根据客户端来发送消息
        //先包装msg，消息序列化
        int msgId = MsgManager.Instance.getMsgId(msg.GetType());
        if (msgId == 0)
        {
            Debug.LogError($"未根据消息类型 {msg.GetType().Name} 找到消息id,发送失败");
            return;
        }
        //TODO 根据配置的序列化方式进行消息序列化
        MsgSerializeType serializeType = (MsgSerializeType)LocalConfig.Instance.msgConfig.serializeType;
        byte[] serializeMsg = MsgManager.Instance.serializeMsg(serializeType,msg);
        if (serializeMsg == null)//未序列化成功或未找到序列化脚本
        {
            return;
        }

        //序列化后的消息为byte[]
        MsgWrapper msgWrapper = MsgWrapper.createSendMsgWrapper(msgId,serializeMsg.Length,msg,serializeMsg);
        //然后socket发送
        if (!sendQueue.TryAdd(msgWrapper))
        {
            //TODO 抛出发送消息失败的事件
            Debug.LogError("发送消息队列可能已满，发送消息失败");
        }
    }


    //发送消息
    private void SendMsgToServer()
    {
        MsgWrapper msgWrapper;
        while (true)
        {
            try
            {
                //TODO 判断连接是否存活
                msgWrapper = sendQueue.Take();
                Debug.Log(1);
                MemoryStream stream = new MemoryStream();
                stream.Seek(0, SeekOrigin.Begin);
                // 消息魔术(2字节)+消息长度(4字节)+消息ID(4字节)+消息版本(4字节)+序列化类型(1字节)+消息内容
                MemoryStreamHelper.writeShort(stream,msgWrapper.moshu);
                MemoryStreamHelper.writeInt(stream,msgWrapper.msgSize);
                MemoryStreamHelper.writeInt(stream,msgWrapper.msgId);
                MemoryStreamHelper.writeInt(stream,msgWrapper.version);
                MemoryStreamHelper.writeInt(stream,msgWrapper.version);
                stream.WriteByte((byte)msgWrapper.serializeType);
                byte[] serializeMsg = msgWrapper.sendSerializeMsg;
                stream.Write(serializeMsg,0,serializeMsg.Length);
                socket.Send(stream.ToArray());
            }
            catch (SocketException e)
            {
                socket.Close();
                //抛出连接断开的事件
                break;
            }
        }
    }

    
    //接收消息
    private void ReceiveMsgFromServer()
    {
        while (true)
        {
            try
            {
                byte[] buffer = new byte[1024*8];
                //实际接收到的有效字节数
                int len = 0;
                while ((len = socket.Receive(buffer))> 0) 
                {
                    // Debug.Log(DateTime.Now+"客户端接收到的数据 ： " + Encoding.UTF8.GetString(buffer));
                    if (len == 0)
                    {
                        break;
                    }
                    //TODO 粘包/半包处理
                    List<MsgWrapper> reCeiveMsgs = msgHandler.addBytes(buffer,0,len);
                    if (reCeiveMsgs.Count == 0)
                    {
                        continue;
                    }

                    foreach (var reCeiveMsgByte in reCeiveMsgs)
                    {
                        receiveQueue.Add(reCeiveMsgByte);
                    }
                }


                //TODO 反序列化

            }
            catch (SocketException e)//TODO 判断连接断开的情况

            {
                Debug.LogError("连接已断开："+e.GetType().Name+e);
                status = 4;
                socket.Close();
                //TODO 抛出连接断开的事件
                break;
            }
        }

    }
}
